#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tokens.h"
#include "keywords.h"
#include "lexer.h"

FILE *tape;
int  lookahead, i, locNum = 1;
char lexeme[MAXLEN];

void skipspaces(void){
    int  head;
    while (isspace(head = getc(tape))){
      if( head == 10 ) // '\n'
	 locNum++;
    }
    if (head == '{'){
      while ( (head=getc(tape)) != '}' ){
	if (head == 10)
	  locNum++;
      }
      skipspaces();
      return;
    }
    ungetc(head, tape);
}

int isID(void){
    i = 0;
    lexeme[i] = toupper(getc(tape));
    if (isalpha(lexeme[i])) {
        while (isalnum(lexeme[++i] = toupper(getc(tape))));
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        if (i = iskeyword(lexeme))
            return i;
        return ID;
    }
    ungetc(lexeme[i], tape);
    return 0;
}

int isUINT(void){
    i = 0;
    lexeme[i] = getc(tape);
    if (isdigit(lexeme[i])) {
        if (lexeme[i] == '0') {
            lexeme[1] = 0;
            return UINT;
        }
        while (isdigit(lexeme[++i] = getc(tape)));
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        return UINT;
    }
    ungetc(lexeme[i], tape);
    return 0;
}

int isRELOP(void){
    i = 0;
    switch (lexeme[i] = getc(tape)){
       case '<':
         if ((lexeme[++i] = getc(tape)) == '>'){
	   strcpy(lexeme, "<>");
	   return RELOP;
	 }
	 else if (lexeme[i] == '='){
	   strcpy(lexeme, "<=");
	   return RELOP;
	 }
	 ungetc(lexeme[i], tape);
	 strcpy(lexeme, "<");
	 return RELOP; 
       case '>':
         if ((lexeme[++i] = getc(tape)) == '='){
	   strcpy(lexeme, ">=");
	   return RELOP;
	 }
         ungetc(lexeme[i], tape);
	 strcpy(lexeme, ">");
	 return RELOP;
       case '=':
	 lexeme[i+1]=0;
	 return RELOP;
       default:
	 ungetc(lexeme[i], tape);
	 return 0;
    }
}

int isADD(void){
    i = 0;
    if ( (lexeme[i] = getc(tape)) == '+' ||
          lexeme[i] == '-' ){
       lexeme[i+1] = 0;
       return ADD;
    }
    ungetc(lexeme[i], tape);
    return 0; 
}

int isMUL(void){
    i = 0;
    if ( (lexeme[i] = getc(tape)) == '/' ||
          lexeme[i] == '*' ){
       lexeme[i+1] = 0;
       return MUL;
    }
    ungetc(lexeme[i], tape);
    return 0; 
}
/*
 * floating = UINT ('.' digit* enotation? | enotation) | '.' digit+ enotation?
 *
 * enotation = 'E' ('+'|'-')? digit+
 */
int isenotation(void){
    lexeme[i] = getc(tape);
    if (lexeme[i] == 'E' || lexeme[i] == 'e') {
        lexeme[++i] = getc(tape);
        if (lexeme[i] == '+' || lexeme[i] == '-')
            lexeme[++i] = getc(tape);
        if (isdigit(lexeme[i])) {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            return 1;
        }
        fprintf(stderr, "ilegal exponential notation\n");
        exit(-2);
    }
    ungetc(lexeme[i], tape);
    lexeme[i] = 0;
    return 0;
}

int isNUM(void){
    if (isUINT()) {
        if ((lexeme[i] = getc(tape)) == '.') {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            isenotation();
            return FLOAT;
        }
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        if (isenotation())
            return FLOAT;
        return UINT;
    }
    if ((lexeme[i] = getc(tape)) == '.') {
        if (isdigit(lexeme[++i] = getc(tape))) {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            isenotation();
            return FLOAT;
        }
        ungetc(lexeme[i--], tape);
        ungetc('.', tape);
        return 0;
    }
    ungetc(lexeme[i], tape);
    return 0;
}

int isASGNM(void){
    i = 0;
    if((lexeme[i++]=getc(tape))==':'){
      if((lexeme[i++]=getc(tape))=='='){
        lexeme[i] = 0;
	return ASGNM;
      }
      ungetc(lexeme[--i],tape);
      lexeme[i]=0;
      return lexeme[0];
    }
  ungetc(lexeme[--i],tape);
  return 0;
}

int isLEQ(void){
    i = 0;
    if((lexeme[i++]=getc(tape))=='<'){
      if((lexeme[i++]=getc(tape))=='='){
        lexeme[i] = 0;
	return LEQ;
      }
      ungetc(lexeme[--i],tape);
      lexeme[i]=0;
      return lexeme[0];
    }
  ungetc(lexeme[--i],tape);
  return 0;
}

int isNEQ(void){
    i = 0;
    if((lexeme[i++]=getc(tape))=='<'){
      if((lexeme[i++]=getc(tape))=='>'){
        lexeme[i] = 0;
	return NEQ;
      }
      ungetc(lexeme[--i],tape);
      lexeme[i]=0;
      return lexeme[0];
    }
  ungetc(lexeme[--i],tape);
  return 0;
}

int isGEQ(void){
    i = 0;
    if((lexeme[i++]=getc(tape))=='>'){
      if((lexeme[i++]=getc(tape))=='='){
        lexeme[i] = 0;
	return GEQ;
      }
      ungetc(lexeme[--i],tape);
      lexeme[i]=0;
      return lexeme[0];
    }
  ungetc(lexeme[--i],tape);
  return 0;
}

int isDDOT(void){
  i = 0;
  if((lexeme[i++]=getc(tape))=='.'){
      if((lexeme[i++]=getc(tape))=='.'){
        lexeme[i] = 0;
	return DDOT;
      }
      ungetc(lexeme[--i],tape);
      lexeme[i]=0;
      return lexeme[0];
  }
  ungetc(lexeme[--i],tape);
  return 0;
}

int gettoken(void)
{
    int  token;
    skipspaces();
    if (token = isID())
        return token;
    if (token = isNUM())
        return token;
    if (token = isRELOP())
	return token;
    if (token = isLEQ())
	return token;
    if (token = isGEQ())
	return token;
    if (token = isNEQ())
	return token;
    if (token = isDDOT())
	return token;
    if (token = isADD())
	return token;
    if (token = isMUL())
	return token;
    if (token = isASGNM())
	return token;
    lexeme[1] = 0;
    return lexeme[0] = getc(tape);
}

void match(int expected)
{
    if (expected == lookahead) {
        lookahead = gettoken();
    } 
    else {
        fprintf(stderr, "token mismatch\naborting\n");
        exit(-1);
    }
}
